import * as THREE from "three"
import CameraPoseProxy from "../CameraPoseProxy"
import DollhouseControlsModule from "../module/DollhouseControlsModule"
import Vectors from "../three/Vectors"
import L from "../math/27687"
export default class CameraTouchControls {
  poseProxy: CameraPoseProxy
  cameraCheck: DollhouseControlsModule["cameraCheck"]
  raycaster: any
  movingCamera: boolean
  smoothedTouch0: THREE.Vector2
  smoothedTouch1: THREE.Vector2
  origTouchAxis: THREE.Vector2
  origCenterPt: THREE.Vector2
  plane: THREE.Plane
  originalPinchLength: number
  pointersMoved: (o: any) => any
  poseController: any
  initialPose: any
  intersectionPt: any
  initMove: (n: any) => void
  constructor(e: CameraPoseProxy, t: DollhouseControlsModule["cameraCheck"], i) {
    this.poseProxy = e
    this.cameraCheck = t
    this.raycaster = i
    this.movingCamera = !1
    this.smoothedTouch0 = new THREE.Vector2()
    this.smoothedTouch1 = new THREE.Vector2()
    this.origTouchAxis = new THREE.Vector2()
    this.origCenterPt = new THREE.Vector2()
    this.plane = new THREE.Plane(Vectors.UP.clone(), 0)
    this.originalPinchLength = 0
    this.pointersMoved = (() => {
      const e = new THREE.Vector2()
      const t = new THREE.Vector3()
      const i = new THREE.Vector3()
      const n = new THREE.Vector2()
      const s = new THREE.Vector3()
      return o => {
        if (!this.poseController) return
        this.smoothedTouch0.lerp(o[0].position, 0.2)
        this.smoothedTouch1.lerp(o[1].position, 0.2)
        n.copy(this.smoothedTouch1).sub(this.smoothedTouch0).normalize()
        const a = this.origTouchAxis.angle() - n.angle()
        t.copy(this.initialPose.position)
        const l = new THREE.Vector3(-this.intersectionPt.x, 0, -this.intersectionPt.z)
        t.add(l)
        t.applyAxisAngle(Vectors.UP, a)
        l.negate()
        t.add(l)
        const c = new THREE.Quaternion().copy(this.initialPose.rotation)
        const h = new THREE.Quaternion().setFromAxisAngle(Vectors.UP, a)
        c.premultiply(h)
        const d = this.smoothedTouch0.clone().lerp(this.smoothedTouch1, 0.5)
        const u = new THREE.Vector3()
        i.copy(Vectors.FORWARD).applyQuaternion(c)
        this.castFrom(d.x, i.y < -0.01 ? d.y : this.origCenterPt.y, u)
        if (isNaN(u.x)) return void (this.movingCamera = !1)
        u.x -= this.intersectionPt.x
        u.z -= this.intersectionPt.z
        u.negate()
        u.applyAxisAngle(Vectors.UP, a)
        const p = 1 - 1 / (e.subVectors(this.smoothedTouch0, this.smoothedTouch1).length() / this.originalPinchLength)
        const m = t.add(u).lerp(this.intersectionPt, p).clone()
        const g = s.subVectors(m, this.intersectionPt).length()
        this.cameraCheck(m, c, g) &&
          this.poseController &&
          (this.poseController.updateCameraPosition(m), this.poseController.updateCameraRotation(c), this.poseController.updateCameraFocus(g))
      }
    })()
    this.initMove = (() => {
      const e = new THREE.Vector2()
      const t = new THREE.Ray()
      const i = new THREE.Vector3()
      return n => {
        const s = n[0].position
        const o = n[1].position
        this.smoothedTouch0.copy(s)
        this.smoothedTouch1.copy(o)
        this.originalPinchLength = e.subVectors(s, o).length()
        this.origTouchAxis.copy(o).sub(s).normalize()
        this.origCenterPt.copy(s).lerp(o, 0.5)
        const { pose: a } = this.poseProxy
        this.initialPose = a.clone()
        const l = new THREE.Vector3()
        const c = new THREE.Vector3()
        L.Kh(this.initialPose, l.set(this.origCenterPt.x, this.origCenterPt.y, -1), l)
        L.Kh(this.initialPose, c.set(this.origCenterPt.x, this.origCenterPt.y, 1), c)
        c.sub(l).normalize()
        const h = this.raycaster.picking.pick(l, c)
        h || (t.set(l, c), t.at(a.focalDistance, i))
        this.intersectionPt = h ? h.point : i
        this.plane.set(Vectors.UP.clone(), 0)
        this.plane.translate(new THREE.Vector3(0, this.intersectionPt.y, 0))
      }
    })()
    this.castFrom = (() => {
      const e = new THREE.Ray()
      const t = new THREE.Vector3()
      const i = new THREE.Vector3()
      return (n: number, s: number, r: THREE.Vector3) => {
        L.Kh(this.initialPose, t.set(n, s, -1), t)
        L.Kh(this.initialPose, i.set(n, s, 1), i)
        i.sub(t).normalize()
        e.set(t, i)
        ;(e.intersectPlane(this.plane, r) && !r.equals(t)) || (r.x = NaN)
        r.y = 0
      }
    })()
  }
  castFrom: any
  rawPointerUpdate(e) {
    const t = this.movingCamera
    this.movingCamera = 2 === e.pointers.length && !!this.poseController
    this.movingCamera && (t ? this.pointersMoved(e.pointers) : this.initMove(e.pointers))
  }
  onAccessGranted(e) {
    this.poseController = e
  }
  onAccessRevoked(e) {
    this.poseController = void 0
    this.movingCamera = !1
  }
}
